package CSnab::Model::Pager;

=head
pager for paginate records
=cut

use warnings;
use strict;

use POSIX qw(ceil);
use URI::Escape qw(uri_escape);

use mirt::Core::Exception;

use base qw/mirt::Core::Constructor/;

sub init {
	my $self = shift;
	
	my %params = (
			pager_width    => 5,  #количество страниц в пейджере
			items_per_page => 10, #число записей на страничку
			force          => [], #список полей исключаемых из get-параметров url
			prefix         => '', #префикс страницы пейджере (для нескольких на одной странице)
			@_,
		);
	my $page_id = $params{prefix} . 'page';
	$params{force} = ref $params{force} eq 'ARRAY' ? $params{force} : [$params{force}];
	$params{force} = { map {$_, 1} (@{$params{force}},  $page_id) };
	$self->SUPER::init(%params, pager_middle => int(($params{pager_width} - 1) / 2), page_id => $page_id);
}

sub paginate {
	my $self = shift;
	my %params = (request => '', count => 0, @_);

	throw new mirt::Core::Exception('undefined request object for pager->paginate...')
		unless $params{request};
	
	my $request = $params{request};
	
	$self->{items_per_page} = 10
		unless $self->{items_per_page} =~ /^\d+$/;
	
	my $pager_width    = $self->{pager_width};
	my $total_items    = $params{count};
	my $current_page   = $request->param($self->{page_id}) || 1;
	my $total_pages    = ceil($total_items / $self->{items_per_page}) || 1;
	my $pager_middle   = $self->{pager_middle};
	my $items_per_page = $self->{items_per_page};
	my $init_last_page = $request->param('last_page') || 0;
	
	$current_page = 1
		unless $current_page =~ /^\d{1,6}$/;
	
	$current_page = $total_pages
		if $current_page > $total_pages or $init_last_page eq '1';
	
	my $context = {
			items_per_page => $items_per_page,
			total_items => $total_items, current => $current_page,	
			total_pages => $total_pages, pages   => [],
			limit => 0, offset => 0,
			first => '', last => '', prev => '', next => '',
		};
	
	my ($beginPage, $endPage);
	
	#маленький список
	if ($total_pages <= $pager_width){
		$beginPage = 1;
		$endPage   = $total_pages;
	}#начало списка
	elsif ($current_page <= $pager_middle + 1){
		$beginPage = 1;
		$endPage   = $pager_width;
	}#конец списка
	elsif ($current_page >= $total_pages - $pager_middle){
		$beginPage = $total_pages - $pager_width + 1;
		$endPage   = $total_pages;
	}#середина
	else {
		$beginPage = $current_page - $pager_middle;
		$endPage   = $current_page + $pager_middle;
	}
	
	my $offset = ($current_page - 1) * $items_per_page;
	
	$context->{begin_page} = $beginPage;
	$context->{end_page}   = $endPage;
	$context->{begin_item} = $offset + 1;
	$context->{end_item}   = $current_page != $total_pages
		? $offset + $items_per_page
		: $total_items;
	
	my $suburi = $self->_pager_suburi($request);
	for my $page ($beginPage..$endPage){
		push @{$context->{pages}}, {
				number	=> $page,
				href	=> $self->_pager_link($suburi, $self->{page_id} => $page),
			};
	}#end for
	
	$context->{limit}  = $items_per_page;
	$context->{offset} = $offset;
	
	$context->{first} = $self->_pager_link($suburi, $self->{page_id} => 1)
		if $beginPage != 1;
	$context->{last} = $self->_pager_link($suburi, $self->{page_id} => $total_pages)
		if $endPage != $total_pages;
	$context->{prev} = $self->_pager_link($suburi, $self->{page_id} => $current_page - 1)
		if $current_page != 1;
	$context->{next} = $self->_pager_link($suburi, $self->{page_id} => $current_page + 1)
		if $current_page != $total_pages;

	return $context;
}

sub _pager_suburi {
	my $self = shift;
	my $request = shift;
	my %force = map {$_, 1} @_;
	
	my @pairs;
	for my $param (sort grep ! exists $self->{force}{$_} && ! exists $force{$_}, $request->param){
		my $escape_param = uri_escape($param);
		push @pairs, map {$escape_param . '=' . uri_escape($_)} $request->param($param);
	}

	return '?' . join('&', @pairs, '');
}

sub _pager_link {
	my $self   = shift;
	my $suburi = shift;
	my %params = @_;

	return $suburi . join('&', map {uri_escape($_) . '=' . uri_escape($params{$_})} keys %params);
}

1;
